package org.lep.leetcode.surroundedregions;

import java.util.Arrays;
import java.util.Stack;

/**
 * Source : https://oj.leetcode.com/problems/surrounded-regions/
 *
 * Created by lverpeng on 2017/8/25.
 *
 * Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'.
 *
 * A region is captured by flipping all 'O's into 'X's in that surrounded region.
 *
 * For example,
 *
 * X O O X
 * X X X X
 * X O X X
 * X X O X
 *
 * After running your function, the board should be:
 *
 * X X X X
 * X X X X
 * X X X X
 * X O X X
 */
public class SurroundedRegions {


    /**
     * 将所有被X包围的O替换为X
     * 先找出不被包围的O替换为Y
     * 然后将所有剩下的所有的O替换为X
     * 最后将所有的Y替换为O
     *
     * 其中关键是将不被包围的O替换为Y，也就是要找出所有不被包围的O
     * 从边缘开始，如果边缘处的元素为O则寻找其周围是否有为O的元素，直到没有O或者没有元素
     *
     *
     * @param board
     * @return
     */
    public char[][] solve (char[][] board) {
        if (board.length == 0) {
            return board;
        }
        fillBoard(board, 'O', 'Y');
        replace(board, 'O', 'X');
        fillBoard(board, 'Y', 'O');
        return board;
    }


    /**
     * 将board中的指定元素替换为另外一个
     *
     * @param board
     * @param source
     * @param target
     */
    private void fillBoard (char[][] board, char source, char target) {
        for (int i = 0; i < board.length; i++) {
            fill(board, i, 0, source, target);
            fill(board, i, board[0].length-1, source, target);
        }
        for (int i = 0; i < board[0].length; i++) {
            fill(board, 0, i, source, target);
            fill(board, board.length-1, i, source, target);
        }
    }

    private void fill (char[][] board, int i, int j, char source, char target) {
        if (i < 0 || j < 0 || i >= board.length || j >= board[0].length || board[i][j] != source) {
            return;
        }
        Stack<Position> stack = new Stack<Position>();
        stack.push(new Position(i, j));

        while (stack.size() > 0) {
            Position position = stack.pop();
            board[position.i][position.j] = target;
            if (position.i > 0 && board[position.i-1][position.j] == source) {
                stack.push(new Position(position.i-1, position.j));
            }
            if (position.i < board.length-1 && board[position.i+1][position.j] == source) {
                stack.push(new Position(position.i+1, position.j));
            }
            if (position.j > 0 && board[position.i][position.j-1] == source) {
                stack.push(new Position(position.i, position.j-1));
            }
            if (position.j < board[0].length-1 && board[position.i][position.j+1] == source) {
                stack.push(new Position(position.i, position.j+1));
            }
        }
    }

    /**
     * 将source替换为target
     *
     * @param board
     * @param source
     * @param target
     */
    private void replace (char[][] board, char source, char target) {
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == source) {
                    board[i][j] = target;
                }
            }
        }
    }

    private static void print (char[][] board) {
        for (int i = 0; i < board.length; i++) {
            System.out.println(Arrays.toString(board[i]));
        }
        System.out.println();
    }

    private class Position {
        int i;
        int j;

        public Position(int i, int j) {
            this.i = i;
            this.j = j;
        }
    }

    public static void main(String[] args) {
        SurroundedRegions surroundedRegions = new SurroundedRegions();
        char[][] board = {
                {'X', 'X', 'X', 'X'},
                {'X', 'X', 'X', 'X'},
                {'X', 'O', 'X', 'X'},
                {'X', 'X', 'O', 'X'}
        };
        print(surroundedRegions.solve(board));
    }


}
